[PATCH] zlib: fix pointer alignment
authorjhofstee <jeroen@myspectrum.nl>
Wed, 9 Apr 2025 10:24:13 +0000 (12:24 +0200)
committerJérémy Lal <kapouer@melix.org>
Tue, 24 Mar 2026 21:11:25 +0000 (22:11 +0100)
The function AllocForBrotli prefixes the allocated memory with its
size, and returns a pointer to the region after it. This pointer can
however no longer be suitably aligned. Correct this by allocating
the maximum of the the size of the size_t and the max alignment.

On Arm 32bits the size_t is 4 bytes long, but the alignment is 8 for
some NEON instructions. When Brotli is compiled with optimizations
enabled newer GCC versions will use the NEON instructions and trigger
a bus error killing node.

see https://github.com/google/brotli/issues/1159

PR-URL: https://github.com/nodejs/node/pull/57727
Reviewed-By: Shelley Vohr <shelley.vohr@gmail.com>
Reviewed-By: Tobias Nießen <tniessen@tnie.de>
Reviewed-By: Daniel Lemire <daniel@lemire.me>
Reviewed-By: Gerhard Stöbich <deb2001-github@yahoo.de>
Gbp-Pq: Topic sec
Gbp-Pq: Name 10-zlib-fix-pointer-alignment.patch

src/node_zlib.cc

index 66370e4165979c6494fb031d87931ca195c89dde..a537e766722852fbed922af7bc84419a20b26edc 100644 (file)
@@ -493,20 +493,22 @@ class CompressionStream : public AsyncWrap, public ThreadPoolWork {
   }
 
   static void* AllocForBrotli(void* data, size_t size) {
-    size += sizeof(size_t);
+    constexpr size_t offset = std::max(sizeof(size_t), alignof(max_align_t));
+    size += offset;
     CompressionStream* ctx = static_cast<CompressionStream*>(data);
     char* memory = UncheckedMalloc(size);
     if (UNLIKELY(memory == nullptr)) return nullptr;
     *reinterpret_cast<size_t*>(memory) = size;
     ctx->unreported_allocations_.fetch_add(size,
                                            std::memory_order_relaxed);
-    return memory + sizeof(size_t);
+    return memory + offset;
   }
 
   static void FreeForZlib(void* data, void* pointer) {
     if (UNLIKELY(pointer == nullptr)) return;
     CompressionStream* ctx = static_cast<CompressionStream*>(data);
-    char* real_pointer = static_cast<char*>(pointer) - sizeof(size_t);
+    constexpr size_t offset = std::max(sizeof(size_t), alignof(max_align_t));
+    char* real_pointer = static_cast<char*>(pointer) - offset;
     size_t real_size = *reinterpret_cast<size_t*>(real_pointer);
     ctx->unreported_allocations_.fetch_sub(real_size,
                                            std::memory_order_relaxed);